<?php

namespace DesignPatterns;

// 简单工厂:简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类。这样做的好处是，将我们许多的业务使用到对具体实现类的依赖转移到了工厂类里面，在我们以后想替换实现类的时候只需要修改工厂，而不需要去每个业务里面修改替换。

// 简单工厂与抽象工厂各自的使用场景
// 简单工厂实例化的类具有相同的接口或者基类，在子类比较固定并不需要扩展时，可以使用简单工厂。
// 而如果要增加一个产品，则需要修改工厂类，增加if/else分支，或者增加一个case分支,这违反了开放封闭原则(对扩展开放，对修改关闭)
// 此时就可以考虑使用抽象工厂

// 简单工厂与实现类之间为一对多的关系
// 抽象工厂与实现类之间是一对一的关系


// 抽象工厂模式的好处就在于将工厂和产品之间的耦合降低，将具体产品的构造过程放在了具体工厂类里面。
// 在以后扩展产品的时候方便很多，只需要添加一个工厂类，一个产品类，就能方便的添加产品，而不需要修改原有的代码。
// 抽象工厂模式符合软件开发中的OCP原则（open close principle），对扩展开放，对修改关闭。

/**
 * 设计模式-抽象工厂模式
 * 简单工厂模式：
 * ①抽象DB：接口中定义抽象一些增删改查的方法
 * ②实现DB接口:创建mysql sqlserver等数据库具体实现类
 * ③抽象工厂：定义抽象创建DB实现类实例的方法
 * ④实现抽象接口：为②中的实现类分别创建一个实现工厂类
 * 作用：
 * 加入新的需求增加，只需要另外写一个类（该类继承虚拟基类）,
 * 在类中完成相应的功能,而且大大的降低了耦合度，
 * 方便日后的维护及扩展，而不用改变原有代码
 */

//DB接口
interface DB
{
    public function connect();
}

//mysql
class mysqlDb implements DB
{
    public function connect()
    {
        echo 'this is obj of mysql;' . PHP_EOL;
    }
}

//oracle
class oracleDb implements DB
{
    public function connect()
    {
        echo 'this is obj of oracle;' . PHP_EOL;
    }
}

//工厂接口(负责创建对象)
interface Factory
{
    public static function creatDB();
}

//factory of mysql
class FactoryOfMysql implements Factory
{
    public static function creatDB() : mysqlDb
    {
        return new mysqlDb();
    }
}

//factory of mysql
class FactoryOfOracle implements Factory
{
    public static function creatDB() : oracleDb
    {
        return new oracleDb();
    }
}

FactoryOfOracle::creatDB()
    ->connect();
FactoryOfMysql::creatDB()
    ->connect();


//假如想扩展一个sqlserver数据库驱动，只需如下操作

//sqlserver驱动
class sqlServerDB implements DB
{
    public function connect()
    {
        echo 'this is obj of sqlserver;' . PHP_EOL;
    }
}

//工厂
class FactorySqlServer implements Factory
{
    public static function creatDB() : sqlServerDB
    {
        return new sqlServerDB();
    }
}

FactorySqlServer::creatDB()
    ->connect();


